{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "1da16f86-c144-4a7e-932e-431719e0924c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test set size: 10000\n",
      "Training set size: 60000\n",
      "Number of training samples: 43360\n",
      "Number of cross-validation samples: 10850\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import torchvision\n",
    "import torchvision.transforms as transforms\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "label_size = 18 # Label size\n",
    "ticklabel_size = 14 # Tick label size\n",
    "    \n",
    "# Define a transform to normalize the data\n",
    "transform = transforms.Compose([\n",
    "    transforms.ToTensor()\n",
    "])\n",
    "\n",
    "# Load test data from the MNIST\n",
    "testset = torchvision.datasets.MNIST(root='./Data', train=False, download=False, transform=transform)\n",
    "print(f\"Test set size: {len(testset)}\")\n",
    "\n",
    "# Load training data from the MNIST\n",
    "trainset = torchvision.datasets.MNIST(root='./Data', train=True, download=False, transform=transform)\n",
    "print(f\"Training set size: {len(trainset)}\")\n",
    "\n",
    "# Rate of trX and cvX\n",
    "tr_cv_rate = 0.8\n",
    "\n",
    "# Create a list to store indices for each class unique()\n",
    "class_indices = [[] for _ in range(10)]  # 10 classes in MNIST\n",
    "\n",
    "# Populate class_indices\n",
    "for idx, (_, label) in enumerate(trainset):\n",
    "    class_indices[label].append(idx)\n",
    "\n",
    "# Calculate the number of samples for each class in training and validation sets\n",
    "train_size_per_class = int(tr_cv_rate * min(len(indices) for indices in class_indices))\n",
    "val_size_per_class = min(len(indices) for indices in class_indices) - train_size_per_class\n",
    "\n",
    "# Create balanced train and validation sets\n",
    "train_indices = []\n",
    "val_indices = []\n",
    "for indices in class_indices:\n",
    "    train_indices.extend(indices[:train_size_per_class])\n",
    "    val_indices.extend(indices[train_size_per_class:train_size_per_class + val_size_per_class])\n",
    "\n",
    "# Create Subset datasets\n",
    "from torch.utils.data import Subset\n",
    "trX = Subset(trainset, train_indices)\n",
    "cvX = Subset(trainset, val_indices)\n",
    "\n",
    "print(f\"Number of training samples: {len(trX)}\")\n",
    "print(f\"Number of cross-validation samples: {len(cvX)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "7853553f-c950-4851-b610-3c4897436153",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "image_channels is 1\n",
      "tensor([[0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],\n",
      "        [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n",
      "        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],\n",
      "        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],\n",
      "        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n",
      "        [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n",
      "        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n",
      "        [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],\n",
      "        [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],\n",
      "        [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.]])\n"
     ]
    }
   ],
   "source": [
    "batch_size = 42 # Define training batch 1，\n",
    "\n",
    "def one_hot_collate(batch):\n",
    "    data = torch.stack([item[0] for item in batch])\n",
    "    labels = torch.tensor([item[1] for item in batch])\n",
    "    one_hot_labels = torch.zeros(labels.size(0), 10)  # 10 classes in MNIST 【0，1，0，0】\n",
    "    one_hot_labels.scatter_(1, labels.unsqueeze(1), 1)\n",
    "    return data, one_hot_labels\n",
    "\n",
    "trLoader = torch.utils.data.DataLoader(trX, batch_size=batch_size, shuffle=True, num_workers=0, collate_fn=one_hot_collate)\n",
    "cvLoader = torch.utils.data.DataLoader(cvX, batch_size=batch_size, shuffle=False, num_workers=0, collate_fn=one_hot_collate)\n",
    "teLoader = torch.utils.data.DataLoader(testset, batch_size=batch_size, shuffle=False, num_workers=0, collate_fn=one_hot_collate)\n",
    "\n",
    "# Get a batch of training data\n",
    "dataiter = iter(trLoader)\n",
    "data, labels = next(dataiter)\n",
    "\n",
    "image_channels = data[0].numpy().shape[0]\n",
    "print(f'image_channels is {image_channels}')\n",
    "print(labels)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "93603103-03f4-491e-aaaf-72376bffad95",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CNN(\n",
      "  (conv1): Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "  (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n",
      "  (conv2): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "  (pool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n",
      "  (fc1): Linear(in_features=3136, out_features=100, bias=True)\n",
      "  (fc2): Linear(in_features=100, out_features=10, bias=True)\n",
      "  (softmax): Softmax(dim=1)\n",
      ")\n"
     ]
    }
   ],
   "source": [
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    "\n",
    "class CNN(nn.Module):\n",
    "    def __init__(self, image_channels, num_classes):\n",
    "        super(CNN, self).__init__()\n",
    "        \n",
    "        # First convolutional layer\n",
    "        self.conv1 = nn.Conv2d(in_channels=image_channels, out_channels=32, kernel_size=3, padding=1)\n",
    "        self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)\n",
    "        \n",
    "        # Second convolutional layer\n",
    "        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)\n",
    "        self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)\n",
    "        \n",
    "        # Fully connected layers\n",
    "        self.fc1 = nn.Linear(64 * 7 * 7, 100)  # After two 2x2 max pools, 28x28 -> 7x7\n",
    "        self.fc2 = nn.Linear(100, num_classes)  # 10 classes output\n",
    "\n",
    "        # Softmax\n",
    "        self.softmax = nn.Softmax(dim=1)\n",
    "        \n",
    "    def forward(self, x):\n",
    "        # Remove the reshape operation and directly use x\n",
    "        x = F.relu(self.conv1(x))\n",
    "        x = self.pool1(x)\n",
    "        \n",
    "        # Second conv layer\n",
    "        x = F.relu(self.conv2(x))\n",
    "        x = self.pool2(x)\n",
    "        \n",
    "        # Flatten the output for the fully connected layers\n",
    "        x = x.view(-1, 64 * 7 * 7)\n",
    "        \n",
    "        # Fully connected layers\n",
    "        x = F.relu(self.fc1(x))\n",
    "        x = self.fc2(x)\n",
    "        \n",
    "        # Softmax\n",
    "        x = self.softmax(x)\n",
    "        \n",
    "        return x\n",
    "\n",
    "# Initialize the model\n",
    "model = CNN(image_channels, 10)\n",
    "if torch.cuda.is_available():\n",
    "    model = model.cuda()\n",
    "\n",
    "# Display model architecture\n",
    "print(model)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "6e4ac7d6-62d0-479a-96ff-81b5af1a2071",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [1/10], Train Loss: 1.5544, CV Loss: 1.4964\n",
      "Epoch [2/10], Train Loss: 1.4898, CV Loss: 1.4956\n",
      "Epoch [3/10], Train Loss: 1.4830, CV Loss: 1.4898\n",
      "Epoch [4/10], Train Loss: 1.4785, CV Loss: 1.4825\n",
      "Epoch [5/10], Train Loss: 1.4757, CV Loss: 1.4821\n",
      "Epoch [6/10], Train Loss: 1.4734, CV Loss: 1.4815\n",
      "Epoch [7/10], Train Loss: 1.4726, CV Loss: 1.4810\n",
      "Epoch [8/10], Train Loss: 1.4717, CV Loss: 1.4791\n",
      "Epoch [9/10], Train Loss: 1.4709, CV Loss: 1.4817\n",
      "Epoch [10/10], Train Loss: 1.4707, CV Loss: 1.4778\n"
     ]
    }
   ],
   "source": [
    "# Define loss function and optimizer\n",
    "criterion = nn.CrossEntropyLoss() # Loss\n",
    "optimizer = torch.optim.Adam(model.parameters()) # Adam\n",
    "\n",
    "# Lists to store losses\n",
    "train_losses = []\n",
    "cv_losses = []\n",
    "\n",
    "# Number of epochs\n",
    "num_epochs =10\n",
    "\n",
    "for epoch in range(num_epochs):\n",
    "    model.train()\n",
    "    batch_losses = []\n",
    "    \n",
    "    for batch_x, batch_y in trLoader:\n",
    "        # Forward pass\n",
    "        outputs = model(batch_x)\n",
    "        loss = criterion(outputs, batch_y)\n",
    "        \n",
    "        # Backward pass and optimize\n",
    "        optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        \n",
    "        batch_losses.append(loss.item())\n",
    "    \n",
    "    # Calculate average training loss for this epoch\n",
    "    avg_train_loss = sum(batch_losses) / len(batch_losses)\n",
    "    train_losses.append(avg_train_loss)\n",
    "    \n",
    "    # Evaluate on cross-validation set\n",
    "    model.eval()\n",
    "    cv_batch_losses = []\n",
    "    with torch.no_grad():\n",
    "        for cv_x, cv_y in cvLoader:\n",
    "            cv_outputs = model(cv_x)\n",
    "            cv_loss = criterion(cv_outputs, cv_y)\n",
    "            cv_batch_losses.append(cv_loss.item())\n",
    "    \n",
    "    avg_cv_loss = sum(cv_batch_losses) / len(cv_batch_losses)\n",
    "    cv_losses.append(avg_cv_loss)\n",
    "    \n",
    "    print(f'Epoch [{epoch+1}/{num_epochs}], Train Loss: {avg_train_loss:.4f}, CV Loss: {avg_cv_loss:.4f}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "f57467c0-635a-4eaf-87b5-6214580dbdc0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy on training set: 99.31%\n",
      "Accuracy on cross-validation set: 98.33%\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1cAAAHUCAYAAADWedKvAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAB0g0lEQVR4nO3dd3iUZdrG4Wtm0nsnCRASIIQmTRABKRGUoijF3mDFde3rZ1nFFcW1sHbcRXHtXVlFWHujCAoKCEEUCC2hBDCBkN5n3u+PSSYZkkBCApNMfudxzJHM2+aeMEEun+e5X5NhGIYAAAAAAE1idnUBAAAAAOAOCFcAAAAA0AwIVwAAAADQDAhXAAAAANAMCFcAAAAA0AwIVwAAAADQDAhXAAAAANAMCFcAAAAA0AwIVwAAAADQDAhXANoMk8nUoMfy5cub9DqzZ8+WyWQ6oXOXL1/eLDW0dNOnT1d8fHyDjrXZbHr77bc1ZswYRUREyNPTU1FRUTr//PP16aefymazndxim2jjxo0ymUy699576z1m+/btMplMuu222xp83bo+Z6NGjdKoUaOOe256erpMJpPeeOONBr9elc2bN2v27NlKT0+vta8xf67NzWQy6ZZbbnHJawNAFQ9XFwAAp8rq1audnj/88MNatmyZli5d6rS9Z8+eTXqd6667TuPGjTuhcwcMGKDVq1c3uQZ3UVJSokmTJumbb77RZZddpvnz5ys6OlpZWVn66quvdPHFF2vBggW68MILXV1qvfr27avTTz9db731lh599FFZLJZax7z++uuSpBkzZjTptV544YUmnd8Qmzdv1kMPPaRRo0bVClKzZs3SX//615NeAwC0VIQrAG3GmWee6fQ8MjJSZrO51vajFRUVyc/Pr8Gv06FDB3Xo0OGEagwKCjpuPW3JHXfcoa+//lpvvvmmrrnmGqd9U6ZM0d13363i4uJ6zy8vL5fJZJKHh2v/czdjxgzddNNN+vLLL3X++ec77bNarXrrrbd0+umnq2/fvk16HVeH8i5durj09QHA1ZgWCAA1jBo1Sr1799aKFSs0dOhQ+fn56dprr5UkLViwQOeee65iYmLk6+urHj166N5771VhYaHTNeqarhUfH6/zzz9fX331lQYMGCBfX191795dr732mtNxdU0LnD59ugICArRjxw5NmDBBAQEB6tixo+68806VlpY6nb9v3z5ddNFFCgwMVEhIiK688kqtXbu2QVPAsrKydNNNN6lnz54KCAhQVFSUzj77bK1cudLpuKopZU899ZSeeeYZJSQkKCAgQEOGDNFPP/1U67pvvPGGkpKS5O3trR49euitt946Zh1VDh48qFdeeUVjx46tFayqJCYmqk+fPpKqf3Zvv/227rzzTrVv317e3t7asWOHJOm1115T37595ePjo7CwME2ePFlbtmxxut6uXbt02WWXKTY2Vt7e3mrXrp1Gjx6tlJQUxzFLly7VqFGjFB4eLl9fX8XFxWnq1KkqKiqq971cccUV8vX1dYxQ1fTNN98oIyOj0Z+zutQ1LXD//v265JJLFBgYqODgYF166aU6ePBgrXPXrVunyy67TPHx8fL19VV8fLwuv/xy7d6923HMG2+8oYsvvliSlJyc7JhKW/XZqmtaYElJiWbOnKmEhAR5eXmpffv2uvnmm5WTk+N0XEN/R5oiOztbN910k9q3by8vLy917txZf//732v9Hn344YcaPHiwgoOD5efnp86dOzv+fCT7VNVHHnlESUlJ8vX1VUhIiPr06aPnnnuu2WoF0DoxcgUARzlw4ICuuuoq/e1vf9Njjz0ms9n+/6G2b9+uCRMm6Pbbb5e/v7+2bt2qxx9/XGvWrKk1tbAuGzdu1J133ql7771X7dq10yuvvKIZM2aoa9euGjFixDHPLS8v1wUXXKAZM2bozjvv1IoVK/Twww8rODhYDzzwgCSpsLBQycnJys7O1uOPP66uXbvqq6++0qWXXtqg952dnS1JevDBBxUdHa2CggItWrRIo0aN0pIlS2r9o/35559X9+7dNXfuXEn2KWETJkxQWlqagoODJdn/Mf6nP/1JF154oZ5++mnl5uZq9uzZKi0tdfxc67Ns2TKVl5dr0qRJDaq/ysyZMzVkyBC9+OKLMpvNioqK0pw5c3Tffffp8ssv15w5c3T48GHNnj1bQ4YM0dq1a5WYmChJmjBhgqxWq5544gnFxcXp0KFDWrVqlSMIpKen67zzztPw4cP12muvKSQkRBkZGfrqq69UVlZW7whncHCwpk6dqgULFigrK0uRkZGOfa+//rp8fHx0xRVXSGr656ym4uJijRkzRvv379ecOXPUrVs3ff7553V+JtLT05WUlKTLLrtMYWFhOnDggObPn69BgwZp8+bNioiI0HnnnafHHntM9913n55//nkNGDBAUv0jVoZhaNKkSVqyZIlmzpyp4cOH69dff9WDDz6o1atXa/Xq1fL29nYc35TfkeMpKSlRcnKydu7cqYceekh9+vTRypUrNWfOHKWkpOjzzz+XZJ8+fOmll+rSSy/V7Nmz5ePjo927dzv97J944gnNnj1b999/v0aMGKHy8nJt3bq1VmAE0AYZANBGTZs2zfD393faNnLkSEOSsWTJkmOea7PZjPLycuP77783JBkbN2507HvwwQeNo/967dSpk+Hj42Ps3r3bsa24uNgICwsz/vKXvzi2LVu2zJBkLFu2zKlOScZ///tfp2tOmDDBSEpKcjx//vnnDUnGl19+6XTcX/7yF0OS8frrrx/zPR2toqLCKC8vN0aPHm1MnjzZsT0tLc2QZJx22mlGRUWFY/uaNWsMScb7779vGIZhWK1WIzY21hgwYIBhs9kcx6Wnpxuenp5Gp06djvn6//znPw1JxldffdWgeqt+diNGjHDafuTIEcPX19eYMGGC0/Y9e/YY3t7exhVXXGEYhmEcOnTIkGTMnTu33tf46KOPDElGSkpKg2qqq75nnnnGse3w4cOGt7e3ceWVV9Z5TmM/ZyNHjjRGjhzpeD5//nxDkvG///3P6bg///nPx/1MVFRUGAUFBYa/v7/x3HPPObZ/+OGHtT6jVaZNm+b05/rVV18ZkownnnjC6bgFCxYYkoyXXnrJsa2hvyP1kWTcfPPN9e5/8cUX6/w9evzxxw1JxjfffGMYhmE89dRThiQjJyen3mudf/75Rr9+/Y5bE4C2h2mBAHCU0NBQnX322bW279q1S1dccYWio6NlsVjk6empkSNHSlKt6WV16devn+Li4hzPfXx81K1bN6dpV/UxmUyaOHGi07Y+ffo4nfv9998rMDCwVjONyy+//LjXr/Liiy9qwIAB8vHxkYeHhzw9PbVkyZI63995553n1JyhanpeVU2pqanav3+/rrjiCqdpkp06ddLQoUMbXFNjTZ061en56tWrVVxcrOnTpztt79ixo84++2wtWbJEkhQWFqYuXbroySef1DPPPKMNGzbU6kTYr18/eXl56frrr9ebb76pXbt21Xp9q9WqiooKx6PqGiNHjlSXLl2cpga+++67Ki0tdZpy1tTPWU3Lli1TYGCgLrjgAqftVaNkNRUUFOiee+5R165d5eHhIQ8PDwUEBKiwsLDRr1ularTn6J/9xRdfLH9/f8fPvkpTfkcaUou/v78uuugip+1VtVXVMmjQIEnSJZdcov/+97/KyMioda0zzjhDGzdu1E033aSvv/5aeXl5Ta4PgHsgXAHAUWJiYmptKygo0PDhw/Xzzz/rkUce0fLly7V27Vp9/PHHknTMpgpVwsPDa23z9vZu0Ll+fn7y8fGpdW5JSYnj+eHDh9WuXbta59a1rS7PPPOMbrzxRg0ePFgLFy7UTz/9pLVr12rcuHF11nj0+6ma3lV17OHDhyVJ0dHRtc6ta9vRqv6RnZaW1qD6qxz951dVR11/rrGxsY79JpNJS5Ys0dixY/XEE09owIABioyM1G233ab8/HxJ9ulv3333naKionTzzTerS5cu6tKli9Nam9GjR8vT09PxqApOJpNJ1157rTZt2qR169ZJsk8JTEhIUHJysqTm+Zwd/d7r+vOv6+d/xRVXaN68ebruuuv09ddfa82aNVq7dq0iIyMb/bo1X9/Dw8NpGqRk/1lER0c7fvZVmvI70pBaoqOja62HjIqKkoeHh6OWESNGaPHixaqoqNA111yjDh06qHfv3nr//fcd58ycOVNPPfWUfvrpJ40fP17h4eEaPXq0488VQNvFmisAOEpd96haunSp9u/fr+XLlztGESS1qDUW4eHhWrNmTa3tdTUvqMs777yjUaNGaf78+U7bq4LFidRT3+s3pKbk5GR5enpq8eLFuuGGGxr8ukf/+VXVceDAgVrH7t+/XxEREY7nnTp10quvvipJ2rZtm/773/9q9uzZKisr04svvihJGj58uIYPHy6r1ap169bp3//+t26//Xa1a9dOl112mf7zn/84/cxqXn/69Ol64IEH9Nprr8nT01MbNmzQww8/7Ki5uT9nDf1M5Obm6rPPPtODDz7odD+u0tJSx1q8E339ioqKWuvMDMPQwYMHHaNEp0J4eLh+/vlnGYbh9BnJzMxURUWF05/ThRdeqAsvvFClpaX66aefNGfOHF1xxRWKj4/XkCFD5OHhoTvuuEN33HGHcnJy9N133+m+++7T2LFjtXfv3kZ1FwXgXhi5AoAGqPrHWM3F95L0n//8xxXl1GnkyJHKz8/Xl19+6bT9gw8+aND5JpOp1vv79ddfa90frKGSkpIUExOj999/X4ZhOLbv3r1bq1atOu750dHRjlGU+joM7ty5U7/++usxrzNkyBD5+vrqnXfecdq+b98+LV26VKNHj67zvG7duun+++/XaaedpvXr19fab7FYNHjwYD3//POS5DgmKSlJAwcOdDxqds+LjY3VuHHj9P777+v555+X2WzWtGnTHPub+3OWnJys/Px8ffLJJ07b33vvPafnJpNJhmHUet1XXnlFVqvVadvRI5THUvWzPfpnv3DhQhUWFtb7sz8ZRo8erYKCAi1evNhpe9Vnq65avL29NXLkSD3++OOSpA0bNtQ6JiQkRBdddJFuvvlmZWdn13lzZQBtByNXANAAQ4cOVWhoqG644QY9+OCD8vT01LvvvquNGze6ujSHadOm6dlnn9VVV12lRx55RF27dtWXX36pr7/+WpKO253v/PPP18MPP6wHH3xQI0eOVGpqqv7xj38oISFBFRUVja7HbDbr4Ycf1nXXXafJkyfrz3/+s3JycjR79uwGTQuU7FMVd+3apenTp+vrr7/W5MmT1a5dOx06dEjffvutXn/9dX3wwQeO9V51CQkJ0axZs3Tffffpmmuu0eWXX67Dhw/roYceko+Pjx588EFJ9iB5yy236OKLL1ZiYqK8vLy0dOlS/frrr47RnBdffFFLly7Veeedp7i4OJWUlDhahY8ZM6ZB72nGjBn6/PPPHW3mO3bs6NjX3J+za665Rs8++6yuueYaPfroo0pMTNQXX3zh+ExUCQoK0ogRI/Tkk08qIiJC8fHx+v777/Xqq68qJCTE6djevXtLkl566SUFBgbKx8dHCQkJdU7pO+ecczR27Fjdc889ysvL07BhwxzdAvv376+rr776hN5XfXbu3KmPPvqo1vaePXvqmmuu0fPPP69p06YpPT1dp512mn744Qc99thjmjBhguPP74EHHtC+ffs0evRodejQQTk5OXruueec1r5NnDhRvXv31sCBAxUZGandu3dr7ty56tSpk6PzJIA2yrX9NADAderrFtirV686j1+1apUxZMgQw8/Pz4iMjDSuu+46Y/369bW6rtXXLfC8886rdc2ju7vV1y3w6Drre509e/YYU6ZMMQICAozAwEBj6tSpxhdffFFnx7ijlZaWGnfddZfRvn17w8fHxxgwYICxePHiWh3gqroFPvnkk7WuIcl48MEHnba98sorRmJiouHl5WV069bNeO2112pd81gq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wdfXV999952ry8BJxMhVKzIqqbIleyot2QEAAICWhnDVipyVGCFPi0lphwqVdqjQ1eUAAAAAqIFw1YoEeHvojIQwSdKyrZkurgYAAABATYSrVia5cmrgslTCFQAAANCSEK5amap1Vz/vylZRWYWLqwEAAABQhXDVynSJ9FfHMF+VWW1ateOwq8sBAAAAUIlw1cpUtWSXmBoIAADg7kaNGqXbb7/d8Tw+Pl5z58495jkmk0mLFy9u8ms313XaEsJVK5RcoyW7YRgurgYAAODUO3jwoG699VZ17txZ3t7e6tixoyZOnKglS5a4ujRJ0sSJE+u9OfDq1atlMpm0fv36Rl937dq1uv7665tanpPZs2erX79+tbYfOHBA48ePb9bXOtobb7yhkJCQk/oapxI3EW6FzuwcLm8PszJyirU9s0Dd2gW6uiQAAIBTJj09XcOGDVNISIieeOIJ9enTR+Xl5fr666918803a+vWrXWeV15eLk9Pz1NS44wZMzRlyhTt3r1bnTp1ctr32muvqV+/fhowYECjrxsZGdlcJR5XdHT0KXstd8HIVSvk62XR0C7hkqSltGQHAADNxTCkskLXPBoxG+emm26SyWTSmjVrdNFFF6lbt27q1auX7rjjDv3000+O40wmk1588UVdeOGF8vf31yOPPCJJmj9/vrp06SIvLy8lJSXp7bffdrr+7NmzFRcXJ29vb8XGxuq2225z7HvhhReUmJgoHx8ftWvXThdddFGdNZ5//vmKiorSG2+84bS9qKhICxYs0IwZM3T48GFdfvnl6tChg/z8/HTaaafp/fffP+Z7P3pa4Pbt2zVixAj5+PioZ8+e+vbbb2udc88996hbt27y8/NT586dNWvWLJWXl0uyjxw99NBD2rhxo0wmk0wmk6Pmo6cFbtq0SWeffbZ8fX0VHh6u66+/XgUFBY7906dP16RJk/TUU08pJiZG4eHhuvnmmx2vdSL27NmjCy+8UAEBAQoKCtIll1yiP/74w7F/48aNSk5OVmBgoIKCgnT66adr3bp1kqTdu3dr4sSJCg0Nlb+/v3r16qUvvvjihGtpCEauWqnk7lFalpqlZVszdcPILq4uBwAAuIPyIumxWNe89n37JS//4x6WnZ2tr776So8++qj8/Wsff/QUswcffFBz5szRs88+K4vFokWLFumvf/2r5s6dqzFjxuizzz7Tn/70J3Xo0EHJycn66KOP9Oyzz+qDDz5Qr169dPDgQW3cuFGStG7dOt122216++23NXToUGVnZ2vlypV11unh4aFrrrlGb7zxhh544AGZTCZJ0ocffqiysjJdeeWVKioq0umnn6577rlHQUFB+vzzz3X11Verc+fOGjx48HF/FjabTVOmTFFERIR++ukn5eXlOa3PqhIYGKg33nhDsbGx2rRpk/785z8rMDBQf/vb33TppZfqt99+01dffaXvvvtOkhQcHFzrGkVFRRo3bpzOPPNMrV27VpmZmbruuut0yy23OAXIZcuWKSYmRsuWLdOOHTt06aWXql+/fvrzn/983PdzNMMwNGnSJPn7++v7779XRUWFbrrpJl166aVavny5JOnKK69U//79NX/+fFksFqWkpDhGJ2+++WaVlZVpxYoV8vf31+bNmxUQENDoOhqDcNVKjeoWJel3rdt9RHkl5QryOTVD3AAAAK60Y8cOGYah7t27N+j4K664Qtdee63T8+nTp+umm26SJMdo11NPPaXk5GTt2bNH0dHRGjNmjDw9PRUXF6czzjhDkn0Uxd/fX+eff74CAwPVqVMn9e/fv97Xvvbaa/Xkk09q+fLlSk5OlmSfEjhlyhSFhoYqNDRUd911l+P4W2+9VV999ZU+/PDDBoWr7777Tlu2bFF6ero6dOggSXrsscdqrZO6//77Hd/Hx8frzjvv1IIFC/S3v/1Nvr6+CggIkIeHxzGnAb777rsqLi7WW2+95Qi18+bN08SJE/X444+rXbt2kqTQ0FDNmzdPFotF3bt313nnnaclS5acULj67rvv9OuvvyotLU0dO3aUJL399tvq1auX1q5dq0GDBmnPnj26++67HZ+HxMREx/l79uzR1KlTddppp0mSOnfu3OgaGotw1UrFhfupS6S/dmYV6ofthzThtBhXlwQAAFo7Tz/7CJKrXrsBqpp5VY0EHc/AgQOdnm/ZsqVWQ4hhw4bpueeekyRdfPHFmjt3rjp37qxx48ZpwoQJmjhxojw8PHTOOeeoU6dOjn3jxo3T5MmT5efnp3fffVd/+ctfHNf88ssvNXz4cA0dOlSvvfaakpOTtXPnTq1cuVLffPONJMlqteqf//ynFixYoIyMDJWWlqq0tLTOEbm6bNmyRXFxcY5gJUlDhgypddxHH32kuXPnaseOHSooKFBFRYWCgoIa9Bo1X6tv375OtQ0bNkw2m02pqamOcNWrVy9ZLBbHMTExMdq0aVOjXqvma3bs2NERrCSpZ8+eCgkJ0ZYtWzRo0CDdcccduu666/T2229rzJgxuvjii9Wli31W12233aYbb7xR33zzjcaMGaOpU6eqT58+J1RLQ7HmqhVztGRn3RUAAGgOJpN9ap4rHg0MS4mJiTKZTNqyZUuDjq8rqBwdzAzDcGzr2LGjUlNT9fzzz8vX11c33XSTRowYofLycgUGBmr9+vV6//33FRMTowceeEB9+/ZVTk6OLrjgAqWkpDgeVaFuxowZWrhwofLy8vT666+rU6dOGj16tCTp6aef1rPPPqu//e1vWrp0qVJSUjR27FiVlZU16L3V1TX66Pf2008/6bLLLtP48eP12WefacOGDfr73//e4Neo62d0rNc8umGIyWSSzWZr1Gsd7zVrbp89e7Z+//13nXfeeVq6dKl69uypRYsWSZKuu+467dq1S1dffbU2bdqkgQMH6t///vcJ1dJQhKtWLLl7ZUv2bVmy2WjJDgAA3F9YWJjGjh2r559/XoWFhbX25+TkHPP8Hj166IcffnDatmrVKvXo0cPx3NfXVxdccIH+9a9/afny5Vq9erVj9MXDw0NjxozRE088oV9//VXp6elaunSpAgMD1bVrV8fD19dXknTJJZfIYrHovffe05tvvqk//elPjmCwcuVKXXjhhbrqqqvUt29fde7cWdu3b2/wz6Jnz57as2eP9u+vHm1cvXq10zE//vijOnXqpL///e8aOHCgEhMTtXv3bqdjvLy8ZLVaj/taKSkpTj/zH3/8UWazWd26dWtwzY1R9f727t3r2LZ582bl5uY6/Xl169ZN//d//6dvvvlGU6ZM0euvv+7Y17FjR91www36+OOPdeedd+rll18+KbVWYVpgKzYoPkz+XhZl5Zdq84E89W5fe/EhAACAu3nhhRc0dOhQnXHGGfrHP/6hPn36qKKiQt9++63mz59/zFGtu+++W5dccokGDBig0aNH69NPP9XHH3/saObwxhtvyGq1avDgwfLz89Pbb78tX19fderUSZ999pl27dqlESNGKDQ0VF988YVsNpuSkpLqfb2AgABdeumluu+++5Sbm6vp06c79nXt2lULFy7UqlWrFBoaqmeeeUYHDx50Cg7HMmbMGCUlJemaa67R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xspkMmnx4sXHPH758uUymUy1Hlu3bnUc8/LLL2v48OEKDQ1VaGioxowZozVr1pzkd9J2nd4pVIE+HsouLNPGfTmuLgcAAABwGZeGq8LCQvXt21fz5s1r1Hmpqak6cOCA45GYmOjYt3z5cl1++eVatmyZVq9erbi4OJ177rnKyMho7vIhydNi1ojEyq6BtGQHAABAG+bhyhcfP368xo8f3+jzoqKiFBISUue+d9991+n5yy+/rI8++khLlizRNddccyJl4jhGJUXq800HtDw1U3ec083V5QAAAAAu0SrXXPXv318xMTEaPXq0li1bdsxji4qKVF5errCwsHqPKS0tVV5entMDDTcyyT5y9eu+XGXll7q4GgAAAMA1WlW4iomJ0UsvvaSFCxfq448/VlJSkkaPHq0VK1bUe869996r9u3ba8yYMfUeM2fOHAUHBzseHTt2PBnlu62oQB+d1j5YkvT9NqYGAgAAoG1y6bTAxkpKSlJSUpLj+ZAhQ7R371499dRTGjFiRK3jn3jiCb3//vtavny5fHx86r3uzJkzdccddzie5+XlEbAaKTkpUpsycrUsNVMXnd7B1eUAAAAAp1yrGrmqy5lnnqnt27fX2v7UU0/pscce0zfffKM+ffoc8xre3t4KCgpyeqBxRnW3t2RfsS1LFVabi6sBAAAATr1WH642bNigmJgYp21PPvmkHn74YX311VcaOHCgiyprW/p2CFGYv5fySyr0y+4jri4HAAAAOOVcOi2woKBAO3bscDxPS0tTSkqKwsLCFBcXp5kzZyojI0NvvfWWJGnu3LmKj49Xr169VFZWpnfeeUcLFy7UwoULHdd44oknNGvWLL333nuKj4/XwYMHJUkBAQEKCAg4tW+wDbGYTRrZLVKLNmRoWWqWBncOd3VJAAAAwCnl0pGrdevWqX///urfv78k6Y477lD//v31wAMPSJIOHDigPXv2OI4vKyvTXXfdpT59+mj48OH64Ycf9Pnnn2vKlCmOY1544QWVlZXpoosuUkxMjOPx1FNPndo31waNquwauDw108WVAAAAAKeeyTAMw9VFtDR5eXkKDg5Wbm4u668a4UhhmU5/5FvZDGnVvWcrNsTX1SUBAAAATdKYbNDq11yh5Qj191L/uFBJ0vJUWrIDAACgbSFcoVklV04NXMbUQAAAALQxhCs0q1FJ9pbsP+44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St9//71GjBjh6nLgxgoKCjRgwAC98MILeuSRR9SvXz/NnTvX1WXBzdx777368ccftXLlSleXgjbi/PPPV7t27fTqq686tk2dOlV+fn56++23XVgZ3JHJZNKiRYs0adIkSfZRq9jYWN1+++265557JEmlpaVq166dHn/8cf3lL39xYbV1Y+QKbi03N1eSFBYW5uJK4O5uvvlmnXfeeRozZoyrS4Eb++STTzRw4EBdfPHFioqKUv/+/fXyyy+7uiy4sbPOOktLlizRtm3bJEkbN27UDz/8oAkTJri4MrQFaWlpOnjwoM4991zHNm9vb40cOVKrVq1yYWX183B1AcDJYhiG7rjjDp111lnq3bu3q8uBG/vggw+0fv16rV271tWlwM3t2rVL8+fP1x133KH77rtPa9as0W233SZvb29dc801ri4Pbuiee+5Rbm6uunfvLovFIqvVqkcffVSXX365q0tDG3Dw4EFJUrt27Zy2t2vXTrt373ZFScdFuILbuuWWW/Trr7/qhx9+cHUpcGN79+7VX//6V33zzTfy8fFxdTlwczabTQMHDtRjjz0mSerfv79+//13zZ8/n3CFk2LBggV655139N5776lXr15KSUnR7bffrtjYWE2bNs3V5aGNMJlMTs8Nw6i1raUgXMEt3Xrrrfrkk0+0YsUKdejQwdXlwI398ssvyszM1Omnn+7YZrVatWLFCs2bN0+lpaWyWCwurBDuJCYmRj179nTa1qNHDy1cuNBFFcHd3X333br33nt12WWXSZJOO+007d69W3PmzCFc4aSLjo6WZB/BiomJcWzPzMysNZrVUrDmCm7FMAzdcsst+vjjj7V06VIlJCS4uiS4udGjR2vTpk1KSUlxPAYOHKgrr7xSKSkpBCs0q2HDhtW6vcS2bdvUqVMnF1UEd1dUVCSz2fmfixaLhVbsOCUSEhIUHR2tb7/91rGtrKxM33//vYYOHerCyurHyBXcys0336z33ntP//vf/xQYGOiYqxscHCxfX18XVwd3FBgYWGtNn7+/v8LDw1nrh2b3f//3fxo6dKgee+wxXXLJJVqzZo1eeuklvfTSS64uDW5q4sSJevTRRxUXF6devXppw4YNeuaZZ3Tttde6ujS4iYKCAu3YscPxPC0tTSkpKQoLC1NcXJxuv/12PfbYY0pMTFRiYqIee+wx+fn56YorrnBh1fWjFTvcSn3zb19//XVNnz791BaDNmvUqFG0YsdJ89lnn2nmzJnavn27EhISdMcdd+jPf/6zq8uCm8rPz9esWbO0aNEiZWZmKjY2VpdffrkeeOABeXl5ubo8uIHly5crOTm51vZp06bpjTfekGEYeuihh/Sf//xHR44c0eDBg/X888+32P+BSbgCAAAAgGbAmisAAAAAaAaEKwAAAABoBoQrAAAAAGgGhCsAAAAAaAaEKwAAAABoBoQrAAAAAGgGhCsAAAAAaAaEKwAAAABoBoQrAACamclk0uLFi11dBgDgFCNcAQDcyvTp02UymWo9xo0b5+rSAABuzsPVBQAA0NzGjRun119/3Wmbt7e3i6oBALQVjFwBANyOt7e3oqOjnR6hoaGS7FP25s+fr/Hjx8vX11cJCQn68MMPnc7ftGmTzj77bPn6+io8PFzXX3+9CgoKnI557bXX1KtXL3l7eysmJka33HKL0/5Dhw5p8uTJ8vPzU2Jioj755JOT+6YBAC5HuAIAtDmzZs3S1KlTtXHjRl111VW6/PLLtWXLFklSUVGRxo0bp9DQUK1du1YffvihvvvuO6fwNH/+fN188826/vrrtWnTJn3yySfq2rWr02s89NBDuuSSS/Trr79qwoQJuvLKK5WdnX1K3ycA4NQyGYZhuLoIAACay/Tp0/XOO+/Ix8fHafs999yjWbNmyWQy6YYbbtD8+fMd+84880wNGDBAL7zwgl5++WXdc8892rt3r/z9/SVJX3zxhSZOnKj9+/erXbt2at++vf70pz/pkUceqbMGk8mk+++/Xw8//LAkqbCwUIGBgfriiy9Y+wUAbow1VwAAt5OcnOwUniQpLCzM8f2QIUOc9g0ZMkQpKSmSpC1btqhv376OYCVJw4YNk81mU2pqqkwmk/bv36/Ro0cfs4Y+ffo4vvf391dgYKAyMzNP9C0BAFoBwhUAwO34+/vXmqZ3PCaTSZJkGIbj+7qO8fX1bdD1PD09a51rs9kaVRMAoHVhzRUAoM356aefaj3v3r27JKlnz55KSUlRYWGhY/+PP/4os9msbt26KTAwUPHx8VqyZMkprRkA0PIxcgUAcDulpaU6ePCg0zYPDw9FRERIkj788EMNHDhQZ511lt59912tWbNGr776qiTpyiuv1IMPPqhp06Zp9uzZysrK0q233qqrr75a7dq1kyTNnj1bN9xwg6KiojR+/Hjl5+frxx9/1K233npq3ygAoEUhXAEA3M5XX32lmJgYp21JSUnaunWrJHsnvw8++EA33XSToqOj9e6776pnz56SJD8/P3399df661//qkGDBsnPz09Tp07VM88847jWtGnTVFJSomeffVZ33XWXIiIidNFFF526NwgAaJHoFggAaFNMJpMWLVqkSZMmuboUAICbYc0VAAAAADQDwhUAAAAANAPWXAEA2hRmwwMAThZGrgAAAACgGRCuAAAAAKAZEK4AAAAAoBkQrgAAAACgGRCuAAAAAKAZEK4AAAAAoBkQrgAAAACgGRCuAAAAAKAZ/D8WyrL3NrMKMgAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 1000x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Calculate and print accuracies for training and cross-validation sets\n",
    "model.eval()\n",
    "with torch.no_grad():\n",
    "    # Training set accuracy\n",
    "    tr_correct = 0\n",
    "    tr_total = 0\n",
    "    for images, labels in trLoader:\n",
    "        outputs = model(images)\n",
    "        _, predicted = torch.max(outputs, 1)\n",
    "        _, true_labels = torch.max(labels, 1)\n",
    "        tr_total += labels.size(0)\n",
    "        tr_correct += (predicted == true_labels).sum().item()\n",
    "    \n",
    "    tr_accuracy = 100 * tr_correct / tr_total\n",
    "    \n",
    "    # Test set accuracy\n",
    "    cv_correct = 0\n",
    "    cv_total = 0\n",
    "    for images, labels in cvLoader:\n",
    "        outputs = model(images)\n",
    "        _, predicted = torch.max(outputs, 1)\n",
    "        _, true_labels = torch.max(labels, 1)\n",
    "        cv_total += labels.size(0)\n",
    "        cv_correct += (predicted == true_labels).sum().item()\n",
    "    \n",
    "    cv_accuracy = 100 * cv_correct / cv_total\n",
    "\n",
    "print(f'Accuracy on training set: {tr_accuracy:.2f}%')\n",
    "print(f'Accuracy on cross-validation set: {cv_accuracy:.2f}%')\n",
    "\n",
    "# Plot training and cross-validation losses\n",
    "plt.figure(figsize=(10, 5))\n",
    "plt.plot(range(1, num_epochs+1), train_losses, label='Training Loss')\n",
    "plt.plot(range(1, num_epochs+1), cv_losses, label='Cross-Validation Loss')\n",
    "plt.xlabel('Epoch')\n",
    "plt.ylabel('Loss')\n",
    "plt.title('Training and Cross-Validation Loss')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ef0f37ea-e66c-4d2e-bc55-76ecf62375e5",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
